#region Using References

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using Beaker.Services.Locator;
using Beaker.Services.Tasks.Synchronous;

#endregion

namespace Beaker.Services.Tasks
{
	public abstract class TaskService
		: ITaskService
	{
		// default to use, when there is no service locator or it has none
#if DEBUG
		private static readonly ITaskService _default = new SynchronousTaskService();
#else
		private static readonly ITaskService _default = new TplTaskService();
#endif

		/// <summary>
		/// Gets the default task service.
		/// </summary>
		/// <remarks>
		/// The default task service is either,
		/// 1) The ITaskService as returned by the ServiceLocator
		/// 2) If there is no locator, or no ITaskService returned by the locator, then
		///		a)	If we are in debug, then a synchronous TPL TaskService
		///		b)	if we are in release, the a asychronous TPL TaskService
		/// </remarks>
		public static ITaskService Default
		{
			get
			{
				Contract.Ensures( Contract.Result<ITaskService>() != null );
				return ServiceLocator.Provide<ITaskService>( _default );
			}
		}

		/// <summary>
		/// Creates a collection that will group multiple tasks together
		/// </summary>
		/// <typeparam name="T">The type of the results that the takss in the colletion will return</typeparam>
		/// <returns>
		/// The collection to add tasks on
		/// </returns>
		public abstract ITaskCollection<T> CreateCollection<T>();

		/// <summary>
		/// Start the given task
		/// </summary>
		/// <param name="action">The action executing the task</param>
		/// <returns>
		/// The task started
		/// </returns>
		public abstract Task Execute( Action action );

		/// <summary>
		/// Starts the given task and observes the enumerable result one-at-a-time asynchronously
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="func">The func that returns the enumerable</param>
		/// <returns>
		/// An observable with the results
		/// </returns>
		/// <remarks>
		/// Only works when the IEnumerable uses deferred execution (linq)
		/// </remarks>
		public abstract IObservable<T> Observe<T>( Func<IEnumerable<T>> func );

		/// <summary>
		/// Starts the given task and expects a result
		/// </summary>
		/// <typeparam name="T">The type of the result</typeparam>
		/// <param name="func">The function executing the task and returning the result</param>
		/// <returns></returns>
		public abstract Task<T> Execute<T>( Func<T> func );
	}
}